﻿//---------------------------------------------
//            Tasharen Network
// Copyright © 2012-2013 Tasharen Entertainment
//---------------------------------------------

using System;
using System.IO;
using System.Net.Sockets;
using System.Collections.Generic;
using System.Net;
using System.Threading;

namespace TNet
{
    // 连接频道管理
    public class ChannelManager
    {
        public ChannelManager()
        {
            Pool<SendData>.MaxNum = 100;
            Instance = this;
        }

        public static ChannelManager Instance;

        Thread mThreadSend;
        Thread mThreadReceive;

        public bool IsStop = false; // 是否停止

        // 初始化
        public bool Init()
        {
            mThreadSend = new Thread(ThreadSend);
            mThreadReceive = new Thread(ThreadReceive);

            mThreadSend.Start();
            mThreadReceive.Start();

            return true;
        }

        public void Release()
        {
            IsStop = true;
            if (mThreadSend != null)
                mThreadSend.Abort();
            if (mThreadReceive != null)
                mThreadReceive.Abort();
        }

        // 主线程调用
        List<Packet> MainThreadReceiveList = new List<Packet>();
        public void UpdateMainThread()
        {
            if (ReceivePacketList.size != 0)
                return;

            lock (WaitReceiveLock)
            {
                for (int i = 0; i < ReceivePacketList.size; ++i)
                {
                    MainThreadReceiveList.Add(ReceivePacketList[i]);
                }

                ReceivePacketList.Release();
            }

            Packet packet = null;
            for (int i = 0; i < MainThreadReceiveList.size; ++i)
            {
                packet = MainThreadReceiveList[i];
                packet.callback.OnEvent(packet.msg);
            }

            MainThreadReceiveList.Release();
        }

        // 当前连接的服务器
        public TcpProtocol[] m_tcpSocket = new TcpProtocol[(int)ServerType.Max];
    
        // 连接某个服务器
        public void Connect(ServerType type, string ip, int port)
        {
            if (m_tcpSocket[(int)type] != null)
                Disconnect(type);

            TcpProtocol tcp = new TcpProtocol();
            tcp.serverType = type;
            tcp.Connect(Tools.ResolveEndPoint(ip, port));
            m_tcpSocket[(int)type] = tcp;
        }

        // 断开连接
        public void Disconnect(ServerType type)
        {
            TcpProtocol socket = m_tcpSocket[(int)type];
            m_tcpSocket[(int)type] = null;
            if (socket != null)
                socket.Disconnect();
        }

        Dictionary<int, CallbackBase> CallbackDictionary = new Dictionary<int,CallbackBase>();

        // 注册回调函数
        public void Register<T>(ServerType type, ushort protocolid, Callback<T>.OnCallback callback) where T : MsgBase, new()
        {
            int key = ((int)type << 24) + protocolid;
            lock (CallbackDictionary)
            {
                if (CallbackDictionary.ContainsKey(key))
                    return;

                CallbackDictionary[key] = new Callback<T>(callback);
            }
        }

        public void Register<T>(ushort protocolid, Callback<T>.OnCallback callback) where T : MsgBase, new()
        {
            int key = protocolid;
            lock (CallbackDictionary)
            {
                if (CallbackDictionary.ContainsKey(key))
                    return;

                CallbackDictionary[key] = new Callback<T>(callback);
            }
        }

        // 取消注册回调
        public void UnRegister(ServerType type, ushort protocolid)
        {
            int key = ((int)type << 24) + protocolid;
            lock (CallbackDictionary)
            {
                CallbackDictionary.Remove(key);
            }
        }

        public void UnRegister(ushort protocolid)
        {
            int key = protocolid;
            lock (CallbackDictionary)
            {
                CallbackDictionary.Remove(key);
            }
        }

        CallbackBase GetCallbackBase(ServerType type, ushort protocolid)
        {
            int key = ((int)type << 24) + protocolid;
            CallbackBase call = null;
            lock (CallbackDictionary)
            {
                if (CallbackDictionary.TryGetValue(protocolid, out call) == false)
                {
                    key = protocolid;
                    if (CallbackDictionary.TryGetValue(protocolid, out call) == false)
                        return null;
                }
            }

            return call;
        }

        // 待发送的数据
        class SendData
        {
            public TcpProtocol socket;
            public MsgBase msg;

            public void Init(TcpProtocol s, MsgBase m)
            {
                socket = s;
                msg = m;
            }

            public void Release()
            {
                socket = null;
                msg = null;
            }
        }

        object WaitListLock = new object();
        List<SendData> WaitSendList = new List<SendData>(); // 待发送的链表

        // 发送消息给某个服
        public void SendMsg(ServerType type, MsgBase msg)
        {
            SendData data = Pool<SendData>.Create();
            data.socket = m_tcpSocket[(int)type];
            data.msg = msg;
            lock (WaitListLock)
            {
                WaitSendList.Add(data);
            }
        }

        public void SendPacket(ServerType type, Buffer buffer)
        {
            TcpProtocol socket = m_tcpSocket[(int)type];
            if (socket != null)
            {
                socket.SendTcpPacket(buffer);
            }
        }

        // 创建发送与解包线程
        void ThreadSend()
        {
            List<SendData> SendTmpList = new List<SendData>();
            while (true)
            {
                if (IsStop)
                    break;

                if (WaitSendList.size != 0)
                    continue;

                lock (WaitListLock)
                {
                    List<SendData> tmp = SendTmpList;
                    SendTmpList = WaitSendList;
                    WaitSendList = tmp;
                }

                foreach (SendData data in SendTmpList)
                {
                    if (data.socket.isConnected)
                    {
                        CallbackBase callback = GetCallbackBase(data.socket.serverType, data.msg.ProtocolID);
                        if (callback == null)
                            return;

                        Buffer buffer = callback.WriterBinary(data.msg);
                        data.socket.SendTcpPacket(buffer);
                    }
                }

                SendTmpList.Clear();
            }
        }

        public class Packet
        {
            public Packet(ServerType st, MsgBase m, CallbackBase c)
            {
                serverType = st;
                msg = m;
                callback = c;
            }

            public ServerType serverType; // 服务器类型
            public MsgBase msg; // 消息
            public CallbackBase callback; // 回调接口
        }

        object WaitReceiveLock = new object();
        List<Packet> ReceivePacketList = new List<Packet>(); // 接收到的消息包

        void ThreadReceive()
        {
            List<Buffer> ReceiveBufferTmpList = new List<Buffer>();
            List<Packet> ReceivePacketTmpList = new List<Packet>();
            TcpProtocol tcp = null;
            while (true)
            {
                if (IsStop)
                    break;

                for (int i = 0; i < m_tcpSocket.Length; ++i)
                {
                    tcp = m_tcpSocket[i];
                    if (tcp != null)
                    {
                        tcp.ReceivePacket(ReceiveBufferTmpList);
                        foreach (Buffer buffer in ReceiveBufferTmpList)
                        {
                            BinaryReader binary = buffer.BeginReading();
                            ushort protid = binary.ReadUInt16();
                            CallbackBase callback = GetCallbackBase(tcp.serverType, protid);
                            if (callback == null)
                                continue;

                            MsgBase msg = callback.ReadByBinary(buffer);
                            msg.ProtocolID = protid;
                            ReceivePacketTmpList.Add(new Packet(tcp.serverType, msg, callback));

                            buffer.Recycle();
                        }

                        ReceiveBufferTmpList.Clear();
                    }
                }

                if (ReceivePacketTmpList.size != 0)
                {
                    lock (WaitReceiveLock)
                    {
                        foreach (Packet packet in ReceivePacketTmpList)
                        {
                            ReceivePacketList.Add(packet);
                        }
                    }

                    ReceivePacketTmpList.Release();
                }

                tcp = null;
            }
        }
    }
}
